package com.eagle.scali.contentcenter.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.eagle.scali.contentcenter.domain.dto.user.UserDTO;
import com.eagle.scali.contentcenter.feignclient.TestBaiduFeignClient;
import com.eagle.scali.contentcenter.feignclient.TestUserCenterFeignClient;
import com.eagle.scali.contentcenter.sentinel.SentinelBlockHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;

@RestController
@ComponentScan(basePackages = { "com.eagle.scali.commoncenter"})
@Slf4j
@RefreshScope
//@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestController {

	@Autowired(required = false)
	private TestUserCenterFeignClient testUserCenterFeignClient;

	@Autowired(required = false)
	private TestBaiduFeignClient testBaiduFeignClient;

	@Autowired(required = false)
	private RestTemplate restTemplate;

//	http://localhost:8050/q?id=1&wxId=aaa
	@GetMapping("/q")
	public UserDTO query(UserDTO userDTO) {
		return this.testUserCenterFeignClient.query(userDTO);
	}

//	http://localhost:8050/p
	@RequestMapping(value = "/p", method = RequestMethod.POST)
	public UserDTO testPost(@RequestBody UserDTO userDTO) {
		//注意这里UserDTO是content-center的，而user-center里定义的是User, 这两个对象会根据字段自动匹配
		return this.testUserCenterFeignClient.testPost(userDTO);
	}

//	http://localhost:8050/baidu
	@GetMapping("/baidu")
	public String queryBaidu() {
		return this.testBaiduFeignClient.index();
	}


	//测试热点限流
	@GetMapping("test-hot")
	@SentinelResource("hot")
	public String testHot(@RequestParam String a, @RequestParam String b){
		return a+" "+b;
	}

	//	http://localhost:8050/test-sentinel-api?a=test
	@GetMapping("/test-sentinel-api")
	public String testSentinelAPI(
			@RequestParam(required = false) String a) {

		String resourceName = "test-sentinel-api";
		ContextUtil.enter(resourceName, "test-wfw");

		// 定义一个sentinel保护的资源，名称是test-sentinel-api
		// 即使在配置里禁用了sentinel, 这个资源也能被sentiel监控到
		Entry entry = null;
		try {

			entry = SphU.entry(resourceName);
			// 被保护的业务逻辑
			if (StringUtils.isBlank(a)) {
				throw new IllegalArgumentException("a不能为空");
			}
			return a;
		}
		// 如果被保护的资源被限流或者降级了，就会抛BlockException
		catch (BlockException e) {
			log.warn("限流，或者降级了", e);
			return "限流，或者降级了";
		} catch (IllegalArgumentException e2) {
			// 统计IllegalArgumentException【发生的次数、发生占比...】
			Tracer.trace(e2);
			return "参数非法！";
		} finally {
			if (entry != null) {
				// 退出entry
				entry.exit();
			}
			ContextUtil.exit();
		}
	}

	@GetMapping("/test-sentinel-resource")
	@SentinelResource(
			value = "test-sentinel-api",
			blockHandler = "block",
			blockHandlerClass = SentinelBlockHandler.class,
			fallback = "fallback"
	)
	public String testSentinelResource(@RequestParam(required = false) String a) {
		if (StringUtils.isBlank(a)) {
			throw new IllegalArgumentException("a cannot be blank.");
		}
		return a;
	}
	/**
	 * 1.5 处理降级
	 * - sentinel 1.6 可以处理Throwable
	 *
	 * @param a
	 * @return
	 */
	public String fallback(String a) {
		return "限流，或者降级了 fallback";
	}


	@GetMapping("/test-rest-template-sentinel/{userId}")
	public UserDTO test(@PathVariable Integer userId) {
		return this.restTemplate
				.getForObject(
						"http://user-center/users/{userId}",
						UserDTO.class, userId);
	}

	@Value("${your.name}")
	private String yourName;

	@GetMapping("/test-config")
	public String testConfiguration() {
		return this.yourName;
	}

}
